package com.freshman_registration.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.freshman_registration.mapper.DormitoryMapper;
import com.freshman_registration.mapper.StudentMapper;
import com.freshman_registration.pojo.Dormitorys;
import com.freshman_registration.pojo.Students;
import com.freshman_registration.service.DormitoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service
public class DormitoryServiceImpl implements DormitoryService {

    @Autowired
    private DormitoryMapper dormitoryMapper;
    @Autowired
    private StudentMapper studentMapper;

    @Override
    public int add(Dormitorys dormitory) {


        return dormitoryMapper.insert(dormitory);
    }



    @Override
    public int update(Dormitorys dormitory) {
        return dormitoryMapper.updateByPrimaryKey(dormitory);
    }


    @Override
    public List<Dormitorys> listAll() {
        return dormitoryMapper.selectAll();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int allocateBed(Dormitorys dormitory) {
        String buildingNo = dormitory.getBuildingNo();
        String roomNo = dormitory.getRoomNo();
        String genderLimit = dormitory.getGenderLimit();

        /* 0. 楼号格式+范围+性别 三重校验 */
        if (!buildingNo.matches("^[MW]\\d{1,2}$")) {
            throw new RuntimeException("楼号格式错误，必须为 M1-M10 或 W1-W10");
        }
        int num = Integer.parseInt(buildingNo.substring(1));
        if (num < 1 || num > 10) {
            throw new RuntimeException("楼号后缀数字只能在 1-10 之间");
        }
        if ((buildingNo.startsWith("M") && !"男".equals(genderLimit)) ||
                (buildingNo.startsWith("W") && !"女".equals(genderLimit))) {
            throw new RuntimeException("楼号前缀与性别不符（M→男，W→女）");
        }

        /* 1. 已有床位 */
        List<Integer> used = dormitoryMapper.selectUsedBeds(buildingNo, roomNo);

        /* 2. 算出缺失 1-4 哪些 */
        List<Integer> miss = IntStream.rangeClosed(1, 4)
                .filter(b -> !used.contains(b))
                .boxed()
                .collect(Collectors.toList());

        if (miss.isEmpty()) {
            return 0; // ✅ 返回 0 表示没有新增
        }

        /* 3. 一次性补齐 */
        dormitoryMapper.insertBatch(buildingNo, roomNo, genderLimit, miss);

        return miss.size(); // ✅ 返回实际新增数量
    }
    public Dormitorys findByStudentId(String studentId) {
        return dormitoryMapper.selectByStudentId(studentId);
    }

    @Override
    @Transactional  // 保证事务一致性
    public void checkIn(String studentId) {
        // 1. 查询学生信息（含性别）
        Students student = studentMapper.selectByStudentId(studentId);
        if (student == null) {
            throw new RuntimeException("学生不存在");
        }
        if (student.getDormId() != null) {
            throw new RuntimeException("已分配宿舍，无需重复操作");
        }

        // 2. 根据学生性别查询空床位（性别限制匹配）
        String gender = student.getGender();  // 学生性别（0-女 1-男）
        Dormitorys emptyBed = dormitoryMapper.findEmptyBedByGender(gender);
        if (emptyBed == null) {
            throw new RuntimeException("当前性别暂无可用床位");
        }

        // 3. 更新宿舍表：绑定学生ID、修改状态、记录分配时间（关键：获取宿舍表的分配时间）
        Long dormId = Long.valueOf(emptyBed.getId());
        int dormUpdateRows = dormitoryMapper.occupyBed(dormId, studentId);
        if (dormUpdateRows <= 0) {
            throw new RuntimeException("床位已被占用，请重新尝试");
        }

        // 3.1 新增：查询刚更新的宿舍记录，获取其 allocate_time
        Dormitorys updatedDorm = dormitoryMapper.selectByPrimaryKey(dormId.intValue());
        Date dormAllocateTime = updatedDorm.getAllocateTime();  // 宿舍表的分配时间

        // 4. 更新学生表：绑定宿舍ID + 同步宿舍表的分配时间（核心修改）
        int studentUpdateRows = studentMapper.setDormIdWithAllocateTime(
                studentId,
                dormId,
                dormAllocateTime  // 传入宿舍表的分配时间
        );
        if (studentUpdateRows <= 0) {
            throw new RuntimeException("学生信息更新失败");
        }

        // 5. 补充更新学生其他状态（保持现有逻辑）
        student.setDormId(emptyBed.getId());
        student.setAllocateTime(dormAllocateTime);  // 同步分配时间
        student.setReportStatus(1);
//        studentMapper.updateByPrimaryKey(student);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchCheckOut(List<Long> dormIds) {
        if (CollUtil.isEmpty(dormIds)) return;

        // 1. 床位放空
        dormitoryMapper.batchCheckOut(dormIds);
        // 2. 学生 dorm_id 置空
        studentMapper.batchClearDorm(dormIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelete(List<Long> dormIds) {
        if (CollUtil.isEmpty(dormIds)) return;

        // 1. 先清学生的外键（防止外键约束）
        studentMapper.batchClearDorm(dormIds);

        // 2. 物理删床位
        dormitoryMapper.batchDeleteByIds(dormIds);
    }
//    确认入住
    /**
     * 确认入住并记录当前时间
     * @param dormId 床位ID
     */
    @Override
    @Transactional
    public void confirmCheckIn(Integer dormId) {
        // 1. 参数校验
        if (dormId == null) {
            throw new RuntimeException("床位ID不能为空");
        }

        // 2. 状态校验
        Dormitorys dormitory = dormitoryMapper.selectByPrimaryKey(dormId);
        if (dormitory == null) {
            throw new RuntimeException("床位不存在");
        }
        if (dormitory.getStudentId() == null) {
            throw new RuntimeException("该床位未分配学生，无法确认入住");
        }
        if (dormitory.getCheckInTime() != null) {
            throw new RuntimeException("该床位已完成入住确认，无需重复操作");
        }

        // 3. 一次性双表同步（宿舍表 + 学生表）
        Date checkInTime = new Date();
        updateCheckInTime(dormId, checkInTime);   // ✅ 只保留这一行
    }
    /**
     * 更新入住确认时间（同时更新宿舍表和学生表）
     * @param dormId 床位ID
     * @param checkInTime 入住确认时间
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCheckInTime(Integer dormId, Date checkInTime) {
        // 1. 参数校验
        if (dormId == null || checkInTime == null) {
            throw new RuntimeException("床位ID和入住时间不能为空");
        }

        // 2. 验证床位存在且已分配学生
        Dormitorys dormitory = dormitoryMapper.selectByPrimaryKey(dormId);
        if (dormitory == null) {
            throw new RuntimeException("床位不存在");
        }
        if (dormitory.getStudentId() == null) {
            throw new RuntimeException("该床位未分配学生，无法更新入住时间");
        }

        // 3. 截断为纯日期（列类型是 DATE）
        LocalDate localDate = checkInTime.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
        java.sql.Date dateOnly = java.sql.Date.valueOf(localDate);   // 用全限定类名

        // 4. 更新宿舍表
        int dormRows = dormitoryMapper.updateCheckInTime(dormId, dateOnly);
        if (dormRows <= 0) {
            throw new RuntimeException("宿舍入住时间更新失败，可能已更新过");
        }

        // 5. 同步更新学生表
        String studentId = String.valueOf(dormitory.getStudentId());
        int studentRows = studentMapper.updateCheckInTime(studentId, dateOnly);
        if (studentRows <= 0) {
            throw new RuntimeException("学生入住时间同步失败");
        }
    }


    //    根据学生ID和姓名查询
    @Override
    public Dormitorys getDormByStudentIdAndName(String studentId, String name) {
        // 1. 校验参数
        if (StringUtils.isEmpty(studentId) || StringUtils.isEmpty(name)) {
            throw new RuntimeException("学号和姓名不能为空");
        }

        // 2. 查询学生（通过学号和姓名双重验证）
        Students student = studentMapper.selectByStudentIdAndName(studentId, name);
        if (student == null) {
            throw new RuntimeException("未找到匹配的学生信息");
        }

        // 3. 查询宿舍信息（复用已有方法）
        Integer dormId = student.getDormId();
        if (dormId == null) {
            throw new RuntimeException("该学生未分配宿舍");
        }
        return dormitoryMapper.selectByPrimaryKey(dormId);
    }

}